package com.zzc.controller;


import com.alibaba.fastjson.JSON;
import com.zzc.domain.Product;
import com.zzc.domain.SpikeOrder;
import com.zzc.handler.AccessLimit;
import com.zzc.mapper.ProductMapper;
import com.zzc.mapper.SpikeOrderMapper;
import com.zzc.repository.ProductESRepository;
import com.zzc.service.impl.ProductServiceImpl;
import com.zzc.utils.RedisUtil;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @author Zzc
 */
@Controller
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private ProductServiceImpl productService;

    @Autowired
    private ProductESRepository productESRepository;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private SpikeOrderMapper spikeOrderMapper;

    //记录商品的库存信息
    public static ConcurrentHashMap<Integer, Boolean> inventoryMap = new ConcurrentHashMap<>();

    private static char[] ops = new char[]{'+', '-', 'X'};

    @PostConstruct
    public void init() {
        List<Product> productList = productService.getProductList();

        //将商品信息添加到elasticsearch中
        //productESRepository.saveAll(productList);

        HashMap<String, Object> map = new HashMap<>(5);
        map.put("product_id", null);
        map.put("product_name", null);
        map.put("product_price", null);
        map.put("product_description", null);
        map.put("product_image", null);

        for (Product product : productList) {

            //将商品信息加入redis
            map.put("product_id", product.getProductId());
            map.put("product_name", product.getProductName());
            map.put("product_price", product.getMiaoshaPrice());
            map.put("product_description", product.getProductDescription());
            map.put("product_image", product.getProductImage());
            redisUtil.hmset("product" + product.getProductId(), map);

            //将商品库存加入redis
            redisUtil.set("productInventory" + product.getProductId(), product.getProductInventory());

        }

    }

    /**
     *
     * @param model 返回的数据
     * @return 返回商品列表
     */
    @GetMapping("/product_list")
    public String productList(Model model) {

        List<Product> productList = productService.getProductList();
        model.addAttribute("productList", productList);
        return "index";
    }

    /**
     * 商品详情页
     * @param productId 商品id
     * @param model 返回的数据
     * @return 返回页面
     */
    @GetMapping("/product_id/{id}")
    public String productDescription(@PathVariable("id") int productId, Model model) {

        Map<Object, Object> map = redisUtil.hmget("product" + productId);

        model.addAttribute("productDetail", map);

        return "description";

    }

    /**
     * 获取验证码
     * @param userId  用户id
     * @param productId 商品id
     * @return 数学算式
     */
    @AccessLimit(seconds = 60,maxCount = 10)
    @GetMapping("/getVC/{userId}/{productId}")
    @ResponseBody
    public String getVC(@PathVariable("userId") int userId, @PathVariable("productId") int productId) {

        //验证码中的3个随机数字
        int i = (int) (Math.random() * 10);
        int j = (int) (Math.random() * 10);
        int t = (int) (Math.random() * 10);

        //随机生成运算符
        Random random = new Random();
        char ops1 = ops[random.nextInt(3) % 3];
        char ops2 = ops[random.nextInt(3) % 3];

        //计算运算结果
        int i1 = 0;
        int res = 0;
        switch (ops1) {
            case '+':
                i1 = i + j;
                break;
            case '-':
                i1 = i - j;
                break;
            case 'X':
                i1 = i * j;
                break;
            default:
                break;
        }
        switch (ops2) {
            case '+':
                res = i1 + t;
                break;
            case '-':
                res = i1 - t;
                break;
            case 'X':
                res = i1 * t;
                break;
            default:
                break;
        }

        String vc = "" + i + ops1 + j + ops2 + t;
        //将运算结果放入redis缓存中，存活时间为10分钟
        redisUtil.set("VC_" + userId + "_" + productId, res, 600);
        return JSON.toJSONString(vc);
    }

    /**
     * 验证算式结果，并返回秒杀url
     * @param userId 用户id
     * @param productId 商品id
     * @param vc 验证结果
     * @return 返回秒杀url中的uuid
     */
    @AccessLimit(seconds = 60,maxCount = 10)
    @RequestMapping("/getUrl/{userId}/{productId}/{vc}")
    @ResponseBody
    public String getUrl(
            @PathVariable("userId") int userId,
            @PathVariable("productId") int productId,
            @PathVariable("vc") int vc) {
        //判断验证结果是否正确
        int i = (int) redisUtil.get("VC_" + userId + "_" + productId);
        if (vc != i) {
            return "验证错误";
        }
        //正确就删除缓存中的验证码结果
        redisUtil.del("VC_" + userId + "_" + productId);

        //生成uuid，放入redis缓存中，并返回给前端
        UUID id = UUID.randomUUID();
        String[] idd = id.toString().split("-");
        String uuid = idd[0] + idd[1];
        redisUtil.set("url_" + userId + "_" + productId, uuid, 10);
        return JSON.toJSONString(uuid);
    }

    /**
     * 秒杀功能
     * @param uuid  秒杀url中的uuid
     * @param userId  用户id
     * @param productId  商品id
     * @return 秒杀结果
     */
    @AccessLimit(seconds = 60,maxCount = 10)    //接口防刷：一分钟内同一个用户只可以请求10次
    @GetMapping("/product_order/{uuid}/{userId}/{productId}")
    @ResponseBody
    public String productOrder(@PathVariable("uuid") String uuid,
                               @PathVariable("userId") int userId,
                               @PathVariable("productId") int productId) {

        //判断前端传来的uuid是否存在（正确）
        String uid = (String) redisUtil.get("url_" + userId + "_" + productId);
        if (uuid == null || !uuid.equals(uid)) {
            return "请求无效";
        }

        //jvm缓存，通过内存标记来判断当前商品是否有库存
        if (inventoryMap.get(productId) != null) {
            return "已售空";
        }

        //获取redis缓存中秒杀之后的商品库存
        long inventory = redisUtil.decr("productInventory" + productId, 1L);
        //如果秒杀后的商品库存小于0，就在jvm缓存inventoryMap添加对应的键值对
        if (inventory < 0) {
            redisUtil.incr("productInventory" + productId, 1L);
            inventoryMap.put(productId, false);
            return "已售空";
        }

        //将秒杀请求放入RabbitMQ消息队列中，进行异步处理，并进行流量削峰
        try {
            Map<String, Integer> map = new HashMap<>();
            map.put("userId", userId);
            map.put("productId", productId);
            rabbitTemplate.convertAndSend("spikeOrder", map);
        } catch (AmqpException e) {
            e.printStackTrace();
            return "秒杀失败";
        }

        return "排队中";
    }

    @Transactional(rollbackFor = Exception.class)
    @GetMapping("/product_order/{userId}/{productId}")
    @ResponseBody
    public String productOrder1(@PathVariable("userId") int userId, @PathVariable("productId") int productId){

        int productInventory = productMapper.getProductInventory(productId);
        if(productInventory > 0){
            if (productMapper.updateInventory(productId)>0){
                SpikeOrder order = new SpikeOrder();
                order.setProductId(productId);
                order.setUserId(userId);
                spikeOrderMapper.insert(order);
            }
        }else {
            return "秒杀失败";
        }

        return "秒杀成功";

    }
}



